package com.benefm.multipar.pad.ble;

import android.bluetooth.BluetoothGatt;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.RequiresApi;

import com.benefm.multipar.pad.BaseApp;
import com.benefm.multipar.pad.event.EventAction;
import com.benefm.multipar.pad.event.MsgEvent;
import com.benefm.multipar.pad.util.filter.Test;
import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleGattCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleScanCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.clj.fastble.utils.HexUtil;

import org.greenrobot.eventbus.EventBus;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BLEManager {

    public static final String DEVICE_BENELIFE_U = "benelife U";
    public static final String DEVICE_BENELIFE_B = "benelife B";
    public static final UUID[] SERVICE_UUIDS = new UUID[]{UUID.fromString("0000bf01-0000-1000-8000-00805f9b34fb")};
    public static final String UUID_SERVICE = "0000bf01-0000-1000-8000-00805f9b34fb";
    public static final String UUID_NOTIFY = "0000bf02-0000-1000-8000-00805f9b34fb";
    public static final String UUID_WRITE = "0000bf03-0000-1000-8000-00805f9b34fb";

    public static final String TAG = BLEManager.class.getSimpleName();
    public static final byte HEAD_1 = -86;
    public static final byte HEAD_2 = -86;
    public static Byte head1Byte = null;
    public static Byte head2Byte = null;
    public static Byte head3Byte = null;
    public static Byte head4Byte = null;
    public static int tempDataCount = 0;
    public static int allDataCount = 0;
    public static final int headNub = 4;
    public static byte[] onePack = null;

    //蓝牙连接后的初始化逻辑是否完成
    private boolean initFinish = false;

    //当前连接的蓝牙设备
    private BleDevice mDevice;

    private static BLEManager manager;

    //呼吸率的数据集合 1秒发送25个数据  共采集25*5 = 125组数据 进行滚动存储
    public LinkedList<Short> respData = new LinkedList<>();

    public static Test test = new Test();

    public String bpWatchData = "";

    public boolean localCount = true;

    //线程池
    public final ExecutorService executorService = Executors.newSingleThreadExecutor();

    public static BLEManager getInstance() {
        if (manager == null) {
            manager = new BLEManager();
        }
        return manager;
    }

    public BleDevice getBleDevice() {
        return mDevice;
    }

    public boolean isConnected() {
        return mDevice != null;
    }

    public boolean isInitFinish() {
        return initFinish;
    }

    public void setInitFinish(boolean initFinish) {
        this.initFinish = initFinish;
    }

    public void disconnect() {
        BleManager.getInstance().disconnect(mDevice);
    }

    public boolean isLocalCount() {
        return localCount;
    }

    public void setLocalCount(boolean localCount) {
        this.localCount = localCount;
    }

    private byte calculateXor(byte[] data) {
        int position = 2;
        byte result = data[position];
        for (int i = position + 1; i < data.length - 1; i++) {
            result = (byte) (result ^ data[i]);
        }
        return result;
    }

    public byte calculateXorWatch(byte[] data) {
        int position = 1;
        byte result = data[position];
        for (int i = position; i < data.length - 1; i++) {
            result = (byte) (result ^ data[i]);
        }
        return result;
    }

    //========================================================================================================================

    /**
     * 单导设备连接成功后初始化
     */
    public void initBleDevice() {
        EventBus.getDefault().post(new MsgEvent<>(EventAction.TIMER_INIT_START));
        setSystemInfo();
        //以下指令等收到上一个指令后再发送下一个指令 A-B-C-D-E
//        setTimeCommand();//20
//        setChannelCommand((byte) 0x01);//30
//        setChannelLeadCommand();//70
//        setUserIdCommand();//60
    }

    //设置系统 安卓系统 0x02
    protected void setSystemInfo() {
        byte[] data = new byte[6];
        data[0] = (byte) 0xAA;
        data[1] = (byte) 0xAA;
        data[2] = (byte) 0x40;
        data[3] = (byte) 0x01;
        data[4] = (byte) 0x02;
        data[5] = calculateXor(data);
        writeData(data);
    }

    //设置通道
    //0x04 四通道
    //0x08 八通道
    //0x01 单通道
    public void setChannelCommand(byte channel) {
        byte[] data = new byte[6];
        data[0] = (byte) 0xAA;
        data[1] = (byte) 0xAA;
        data[2] = (byte) 0x30;
        data[3] = (byte) 0x01;
        data[4] = channel;
        data[5] = calculateXor(data);
        writeData(data);
    }

    //设置时间
    public void setTimeCommand() {
        byte[] data = new byte[11];
        data[0] = (byte) 0xAA;
        data[1] = (byte) 0xAA;
        data[2] = (byte) 0x20;
        data[3] = (byte) 0x06;

        Date date = new Date(System.currentTimeMillis());
        data[4] = (byte) (date.getYear() - 100);
        data[5] = (byte) (date.getMonth() + 1);
        data[6] = (byte) date.getDate();
        data[7] = (byte) date.getHours();
        data[8] = (byte) date.getMinutes();
        data[9] = (byte) date.getSeconds();
        data[10] = calculateXor(data);
        writeData(data);

    }

    //大气压强
    public void getAtmosphericPressure() {
        byte[] data = new byte[5];
        data[0] = (byte) 0xAA;
        data[1] = (byte) 0xAA;
        data[2] = (byte) 0x24;
        data[3] = (byte) 0x00;
        data[4] = calculateXor(data);
        writeData(data);
    }


    //=================================================================================================================================

    public void scanDevice() {
        if (BleManager.getInstance() == null)
            return;
        if (!BleManager.getInstance().isBlueEnable())
            return;
        BleManager.getInstance().scan(new BleScanCallback() {

            @Override
            public void onScanStarted(boolean success) {
                if (BaseApp.isDebug)
                    System.out.println("ble start scanning bluetooth devices");
                EventBus.getDefault().post(new MsgEvent<>(EventAction.SCAN_START));
            }

            @Override
            public void onScanFinished(List<BleDevice> scanResultList) {
                if (BaseApp.isDebug)
                    System.out.println("ble bluetooth scan finish");
                List<BleDevice> list = new ArrayList<>();
                for (BleDevice device : scanResultList) {
                    if (DEVICE_BENELIFE_U.equalsIgnoreCase(device.getName())
                            || DEVICE_BENELIFE_B.equalsIgnoreCase(device.getName()))
                        list.add(device);
                }
                EventBus.getDefault().post(new MsgEvent<>(EventAction.SCAN_FINISH, list));
            }

            @RequiresApi(api = Build.VERSION_CODES.R)
            @Override
            public void onScanning(BleDevice bleDevice) {
                if (DEVICE_BENELIFE_U.equalsIgnoreCase(bleDevice.getName())
                        || DEVICE_BENELIFE_B.equalsIgnoreCase(bleDevice.getName())) {
                    EventBus.getDefault().post(new MsgEvent<>(EventAction.DEVICE_FOUND, bleDevice));
                }
            }
        });
    }


    public void connectDevice(BleDevice bleDevice) {
        BleManager.getInstance().connect(bleDevice, new BleGattCallback() {
            @Override
            public void onStartConnect() {
            }

            @Override
            public void onConnectFail(BleDevice bleDevice, BleException exception) {
                mDevice = null;
                initFinish = false;
                EventBus.getDefault().post(new MsgEvent<>(EventAction.DEVICE_CONNECT_FAIL));
            }

            @Override
            public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {

                mDevice = bleDevice;
                EventBus.getDefault().post(new MsgEvent<>(EventAction.DEVICE_CONNECTED, bleDevice));
                new Handler(Looper.getMainLooper()).postDelayed(() -> notifyDevice(bleDevice), 100);

            }

            @Override
            public void onDisConnected(boolean isActiveDisConnected, BleDevice device, BluetoothGatt gatt, int status) {
                mDevice = null;
                initFinish = false;
                EventBus.getDefault().post(new MsgEvent<>(EventAction.DEVICE_DISCONNECTED, device));
            }
        });
    }


    private void notifyDevice(BleDevice bleDevice) {
        BleManager.getInstance().notify(bleDevice, UUID_SERVICE, UUID_NOTIFY, new BleNotifyCallback() {
            @Override
            public void onNotifySuccess() {
                if (BaseApp.isDebug)
                    Log.i(TAG, "onNotifySuccess");
                initBleDevice();
            }

            @Override
            public void onNotifyFailure(BleException exception) {
                if (BaseApp.isDebug)
                    Log.i(TAG, "onNotifyFailure");
                BleManager.getInstance().disconnectAllDevice();
                BleManager.getInstance().destroy();
                BaseApp.getInstance().initBase();
                EventBus.getDefault().post(new MsgEvent<>(EventAction.DEVICE_DISCONNECTED));
            }

            @Override
            public void onCharacteristicChanged(byte[] data) {
                executorService.submit(new BleHandleThread(data));
            }
        });
    }

    private void writeData(byte[] data) {
        if (BaseApp.isDebug)
            Log.i(TAG, "begin write " + HexUtil.formatHexString(data, true));
        BleManager.getInstance().write(mDevice, UUID_SERVICE, UUID_WRITE, data, new BleWriteCallback() {
            @Override
            public void onWriteSuccess(int current, int total, byte[] justWrite) {
            }

            @Override
            public void onWriteFailure(BleException exception) {
            }
        });
    }

}
